package com.thon.dao.util;

import java.util.List;

import javax.annotation.Resource;

import org.apache.commons.lang3.StringUtils;
import org.apache.log4j.Logger;
import org.hibernate.HibernateException;
import org.hibernate.Query;
import org.hibernate.SQLQuery;
import org.hibernate.SessionFactory;

import com.thon.entity.util.IdEntity;

/**
 * @author manpiaoyi
 * @mail manpiaoyi@126.com
 * @date 2014-10-17
 * @description
 */
public abstract class AbstractDao<E extends IdEntity> implements BaseDao<E> {

	private Logger log=Logger.getLogger(this.getClass());   

	@Resource
	private SessionFactory sessionFactory;
	
	protected Class<E> entityClass;

	public AbstractDao(Class<E> entityClass) {
		this.entityClass = entityClass;
	}
	
	public void save(E entity) {
			sessionFactory.getCurrentSession().persist(entity);
	}

	public void update(E entity) {
			sessionFactory.getCurrentSession().merge(entity);
	}

	public void delete(E entity) {
			sessionFactory.getCurrentSession().delete(entity);
	}
	
	public void delete(int id) {
			sessionFactory.getCurrentSession().delete(get(id));
	}
	
    public List<E> readList(){
    	String querySql = "FROM "+entityClass.getName();
		return findList(querySql,null);
    	
    }
	
    public List<E> readList(String by,Object val){
    	String querySql;
    	if("String".equals(val.getClass().getSimpleName()))
    		querySql = "FROM "+entityClass.getSimpleName()+" b WHERE b."+by+" = '"+val+"'";
    	else 
    		querySql = "FROM "+entityClass.getSimpleName()+" b WHERE b."+by+" = "+val;
		return findList(querySql,null);
    	
    }   
 
    
	public Page<E> readListPage(Page<E> page){
		String querySql = "FROM "+entityClass.getSimpleName();
		return findPage(page,querySql);	
		
	}
	
	public Page<E> readListPage(Page<E> page,String by,Object val){
		String querySql;
    	if("String".equals(val.getClass().getSimpleName()))
    		querySql = "FROM "+entityClass.getSimpleName()+" b WHERE b."+by+" = '"+val+"'";
    	else 
    		querySql = "FROM "+entityClass.getSimpleName()+" b WHERE b."+by+" = "+val;		
		return findPage(page,querySql);	
		
	}	
	
	
	public E getOne(String by,Object val)
	{		
		String querySql;
    	
    		querySql = "FROM "+entityClass.getSimpleName()+" b WHERE b."+by+" = ?";	
		
		return findOne(querySql,null,val);	
		
	}	
	
	
	
	@SuppressWarnings("unchecked")
	public E get(int id){
			E load = (E) sessionFactory.getCurrentSession().get(entityClass,  id);
			return load;
	}
	
	protected Long count(String queryString, Object... values) {
		Query query = sessionFactory.getCurrentSession().createQuery(queryString);
		setParametersToQuery(query, values);
		return (Long)query.uniqueResult();
	}
	
	protected Long countBySql(String sqlString, Object... values) {
		Query query = sessionFactory.getCurrentSession().createSQLQuery(sqlString);
		setParametersToQuery(query, values);
		
		if (query.uniqueResult() == null) {
			return new Long(0);
		}else {
			return Long.parseLong(query.uniqueResult().toString());
		}
	}
	
	@SuppressWarnings("unchecked")
	protected E findOne(String queryString,String cacheName,Object... values){
			try {
				Query query = sessionFactory.getCurrentSession().createQuery(queryString);
				setParametersToQuery(query, values);
				
				return (E) query.uniqueResult();
			} catch (HibernateException e) {
				return null;
			}
	}
	
	@SuppressWarnings("unchecked")
	protected Object findOneBySQL(String sqlString, Object... values){
			try {
				Query query = sessionFactory.getCurrentSession().createSQLQuery(sqlString);				
				setParametersToQuery(query, values);

				return (Object) query.uniqueResult();
			} catch (HibernateException e) {
				return null;
			}
	}
	
	@SuppressWarnings("unchecked")
	protected Object findOneByHql(String sqlString, Object... values){
			try {
				Query query = sessionFactory.getCurrentSession().createQuery(sqlString);				
				setParametersToQuery(query, values);

				return (Object) query.uniqueResult();
			} catch (HibernateException e) {
				return null;
			}
	}
	
	@SuppressWarnings("unchecked")
	protected List<E> findList(String queryString, String cacheName, Object... values){
		try {
			Query query = sessionFactory.getCurrentSession().createQuery(queryString);
			setParametersToQuery(query, values);			
			return (List<E>) query.list();
		} catch (HibernateException e) {
			return null;
		}
	}
	
	@SuppressWarnings("unchecked")
	protected List<E> findListBySqlEntity(String sqlString, String cacheName, Object... values) {
			try {
				SQLQuery query = sessionFactory.getCurrentSession().createSQLQuery(sqlString).addEntity(entityClass);
				setParametersToQuery(query, values);
				
				return (List<E>) query.list();
			} catch (HibernateException e) {
				return null;
			}
	}
	
	@SuppressWarnings("unchecked")
	protected List<Object> findListBySql(String sqlString, Object... values) {
			try {
				Query query = sessionFactory.getCurrentSession().createSQLQuery(sqlString);
				setParametersToQuery(query, values);

				return (List<Object>)query.list();
			} catch (HibernateException e) {
				return null;
			}
	}

	@SuppressWarnings("unchecked")
	protected Page<E> findPage(Page<E> page, String queryString, Object...values) {
		try {
			String countString = getCountQuery(queryString);
			if(page.getAutoCount()) {
				Long totalCount = count(countString, values);
				page.setTotalCount(totalCount);
			}
			queryString = appendOrders(page, queryString);
			Query query = sessionFactory.getCurrentSession().createQuery(queryString);
			setParametersToQuery(query, values);
			
			// 分页
			if(page.getPageNo() >0 && page.getPageSize() >0 ){
				query.setFirstResult(page.getFirst()-1);
				query.setMaxResults(page.getPageSize());
			}
			List<E> resultList = (List<E>)query.list();
			return page.setResult(resultList);
		} catch (HibernateException e) {
			return null;
		}
	}
			
	
	
	
	@SuppressWarnings("unchecked")
	protected Page<E> findPageBySql(Page<E> page, String queryString, String cacheName, Object...values) {
		try {
			String countString = getCountQuery(queryString);
			if(page.getAutoCount()) {
				Long totalCount = countBySql(countString, values);
				page.setTotalCount(totalCount);
			}
			queryString = appendOrders(page, queryString);
			SQLQuery query = sessionFactory.getCurrentSession().createSQLQuery(queryString);
			setParametersToQuery(query, values);
			// 分页
			if(page.getPageNo() >0 && page.getPageSize() >0 ){
				query.setFirstResult(page.getFirst()-1);
				query.setMaxResults(page.getPageSize());
			}
			query.addEntity(entityClass);
			
			List<E> resultList = (List<E>)query.list();
			
			return page.setResult(resultList);
		} catch (HibernateException e) {
			return null;
		}
	}
	
	protected String  setParameterList(String queryString,String string,String separator)
	{
		String[] strArray =  string.split(separator);
		for(int i=0;i<strArray.length;i++)
		{
			
		}
		return queryString;
	}
	
	
	
	private void setParametersToQuery(Query query, Object...values) {
		// set parameters to query
		for(int i=0; i<values.length; i++) {
			query.setParameter(i, values[i]);
		}
	}

	private String getCountQuery(String queryStr) {
		String countQueryStr = queryStr;
		// clean order by or group by
		if (queryStr.toUpperCase().startsWith("SELECT")) {
			countQueryStr = "SELECT COUNT(1) FROM (" + countQueryStr +") temp";
		}else {
			countQueryStr = "FROM " + StringUtils.substringAfter(countQueryStr, "FROM");
			countQueryStr = StringUtils.substringBefore(countQueryStr, "ORDER BY");
			countQueryStr = StringUtils.substringBefore(countQueryStr,"GROUP BY");
			countQueryStr = "SELECT COUNT(*) " + countQueryStr;
		}
		
		return countQueryStr;
	}
	
	private String appendOrders(Page<E> page, String qlString) {
		if(!page.getOrderList().isEmpty()) {
			StringBuffer buffer = new StringBuffer(qlString);
			if(!StringUtils.contains(qlString, "ORDER BY")) {
				buffer.append(" ORDER BY");
			} else {
				buffer.append(",");
			}
			List<String> orderList = page.getOrderList();
			for(int i=0; i<orderList.size(); i++) {
				buffer.append(" " + orderList.get(i));
				if(i + 1 < orderList.size()) {
					buffer.append(",");
				}
			}
			return buffer.toString();
		}
		return qlString;
	}

}
